package com.util;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.dto.JsonCarrierDTO;
import com.dto.PageResDTO;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.metrics.tophits.ParsedTopHits;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * <p>
 *
 * </p>
 *
 * @author zhangqing
 * @since 2021/1/27
 */
public class ElasticSearchUtil {
    /**
     * 将请求参数封装成map ,获取查询体
     * @param must   等于
     * @param mustNot 不等于
     * @param should 或者
     * @param exists 空查询
     *              只能查询null,不能查询空字符串， map.value=isnull 查询空，map.value=notnull 查询非空
     * @return
     */
    public static BoolQueryBuilder getQueryBuilder(Map<String,String> must,
                                                   Map<String,String> mustNot,
                                                   Map<String,String> should,
                                                   Map<String,String> exists

                                                  ){
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        if(!CollectionUtils.isEmpty(must)){
            for(Map.Entry<String,String> entry: must.entrySet()){
                if(StringUtils.isEmpty(entry.getKey()) || StringUtils.isEmpty(entry.getValue() )){
                    continue;
                }
                boolQueryBuilder.must(QueryBuilders.matchQuery(entry.getKey(),entry.getValue()));
            }
        }
        if(!CollectionUtils.isEmpty(mustNot)){
            for(Map.Entry<String,String> entry: mustNot.entrySet()){
                if(StringUtils.isEmpty(entry.getKey()) || StringUtils.isEmpty(entry.getValue() )){
                    continue;
                }
                boolQueryBuilder.mustNot(QueryBuilders.matchQuery(entry.getKey(),entry.getValue()));
            }
        }
        if(!CollectionUtils.isEmpty(should)){
            for(Map.Entry<String,String> entry: should.entrySet()){
                if(StringUtils.isEmpty(entry.getKey()) || StringUtils.isEmpty(entry.getValue() )){
                    continue;
                }
                boolQueryBuilder.mustNot(QueryBuilders.matchQuery(entry.getKey(),entry.getValue()));
            }
        }
        if(!CollectionUtils.isEmpty(exists)){
            for(Map.Entry<String,String> entry: exists.entrySet()){
                if(StringUtils.isEmpty(entry.getKey()) || StringUtils.isEmpty(entry.getValue() )){
                    continue;
                }
                switch (entry.getValue()){
                    case "isnull":
                        boolQueryBuilder.mustNot(QueryBuilders.existsQuery(entry.getKey()));
                        break;
                    case "notnull":
                        boolQueryBuilder.must(QueryBuilders.existsQuery(entry.getKey()));
                        break;
                }

            }
        }



        return boolQueryBuilder;
    }
    /**
     * 根据聚合函数的tophit 返回聚合后的一组相关数据 适合二级桶
     * @param aggregations
     * @param <T>
     * @param
     * @return
     */
    public static <T> List<T> getTopHitsAggrsList(Aggregations aggregations){
        List<Aggregation> aggres = aggregations.asList();
        if (CollectionUtils.isEmpty(aggres)) {
            return null;
        }
        ParsedTerms parsedTopHits = (ParsedTerms) aggres.get(0);
        List<? extends Terms.Bucket> buckets = parsedTopHits.getBuckets();

        if (CollectionUtils.isEmpty(buckets)) {
            return null;
        }
        List<T> list = new ArrayList<>();
        for (Terms.Bucket bucket : buckets) {
            List<Aggregation> aggres3 = bucket.getAggregations().asList();
            if (CollectionUtils.isEmpty(aggres3)) {
                continue;
            }

            ParsedTopHits topHits = (ParsedTopHits) aggres3.get(0);
            if (topHits.getHits() == null || topHits.getHits().getHits().length < 1) {
                continue;
            }
            org.elasticsearch.search.SearchHit hit = topHits.getHits().getHits()[0];
            if (hit == null) {
                continue;
            }
            String json = hit.toString();

            JsonCarrierDTO<T> jsonRoverDTO = JSONObject.parseObject(json,new TypeReference<JsonCarrierDTO>(){});
            T t= jsonRoverDTO.get_source();

            list.add(t);

        }
        return list;
    }

    /**
     * 查询聚合函数 tophits的 返回数量  适合二级桶
     * @param aggregations
     * @return
     */
    public static Integer getTopHitsAggrsCount(Aggregations aggregations){
        List<Aggregation> aggres = aggregations.asList();
        if (CollectionUtils.isEmpty(aggres)) {
            return null;
        }
        ParsedTerms parsedTopHits = (ParsedTerms) aggres.get(0);
        List<? extends Terms.Bucket> buckets = parsedTopHits.getBuckets();

        if (CollectionUtils.isEmpty(buckets)) {
            return null;
        }
        return buckets.size();

    }

    /**
     * 查询聚合函数 tophits分页 适合二级桶
     * @param aggregations
     * @param page
     * @param size
     * @param <T>
     * @return
     */
    public static <T> PageResDTO<T> getTopHitsAggrsPage(Aggregations aggregations,Integer page,Integer size){
        PageResDTO<T> pageRes = new PageResDTO<>(page,size,0,0,null);
        List<T> list = getTopHitsAggrsList(aggregations);
        if(CollectionUtils.isEmpty(list)){
            return null;
        }
        Integer totalSize = getTopHitsAggrsCount(aggregations);
        if(totalSize<1){
            return null;
        }
        Integer totalPage = totalSize%size == 0 ? totalSize/size : totalSize/size + 1;
        return new PageResDTO<>(page,size,totalPage,totalSize,list);
    }
}
